/*
家人们，恶心的写法又来了，如果effect里面嵌套着effect
effect(function effectFn1() {
  effect(function effectFn2(){
    //...
  })
})

一个effectFn的执行，可以理解成一个组件的渲染， effect的嵌套，相当于组件之间的嵌套
*/
const bucket = new WeakMap()

const data = { foo: true, bar: true }

// 注册effect回调
let activeEffect
const effectStack = [] // 新增 effect栈!!!!!!!!!!!!
function effect(fn) {
  const effectFn = () => {
    cleanup(effectFn)
    activeEffect = effectFn
    effectStack.push(effectFn) // fn执行，调用track, 读取activeEffect, 先入栈
    fn()
    effectStack.pop() // 当前effectFn已经注册完毕, 弹出
    activeEffect = effectStack[effectStack.length - 1]
  }
  effectFn.deps = []
  effectFn()
}

function cleanup(effectFn) {
  for (let i = 0; i < effectFn.deps.length; i++) {
    const deps = effectFn.deps[i]
    deps.delete(effectFn)
  }
  effectFn.deps.length = 0
}

function track(target, key) {
  if (!activeEffect) return
  let depsMap = bucket.get(target)
  if (!depsMap) bucket.set(target, (depsMap = new Map()))
  let deps = depsMap.get(key)
  if (!deps) depsMap.set(key, (deps = new Set()))
  deps.add(activeEffect)
  activeEffect.deps.push(deps)
}

function trigger(target, key) {
  const depsMap = bucket.get(target)
  if (!depsMap) return
  const deps = depsMap.get(key)
  if (!deps) return
  const effectsToRun = new Set(deps)
  effectsToRun.forEach((effectFn) => effectFn())
}

const obj = new Proxy(data, {
  get(target, key) {
    track(target, key)
    return Reflect.get(target, key)
  },
  set(target, key, val) {
    Reflect.set(target, key, val)
    trigger(target, key)
    return true
  },
})
// 全局变量
let inner, out

effect(function outEffect() {
  console.log('outEffect')
  effect(function innerEffect() {
    console.log('innerEffect')
    inner = obj.bar
    console.log('inner:', inner)
  })
  out = obj.foo
  console.log('out:', out)
})
/*
========================================================================
此时修改obj.foo, 本应该触发outEffect， 结果只触发了innerEffect
原因是因为注册effect回调时，activeEffect被内层的innerEffect嵌套替换了，导致注册outEffect时，activeEffect指向了innerEffect
为了解决这个问题，就需要一个effect栈，来依次注册effect回调
*/
